home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / lib / python2.4 / tarfile.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2005-10-18  |  54KB  |  1,959 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.4)
  3.  
  4. '''Read from and write to tar format archives.
  5. '''
  6. __version__ = '$Revision: 1.21.2.5 $'
  7. version = '0.6.4'
  8. __author__ = 'Lars Gust\xe4bel (lars@gustaebel.de)'
  9. __date__ = '$Date: 2005/08/27 10:08:21 $'
  10. __cvsid__ = '$Id: tarfile.py,v 1.21.2.5 2005/08/27 10:08:21 loewis Exp $'
  11. __credits__ = 'Gustavo Niemeyer, Niels Gust\xe4bel, Richard Townsend.'
  12. import sys
  13. import os
  14. import shutil
  15. import stat
  16. import errno
  17. import time
  18. import struct
  19. if sys.platform == 'mac':
  20.     raise ImportError, 'tarfile does not work for platform==mac'
  21.  
  22.  
  23. try:
  24.     import grp
  25.     import pwd
  26. except ImportError:
  27.     grp = pwd = None
  28.  
  29. __all__ = [
  30.     'TarFile',
  31.     'TarInfo',
  32.     'is_tarfile',
  33.     'TarError']
  34. NUL = '\x00'
  35. BLOCKSIZE = 512
  36. RECORDSIZE = BLOCKSIZE * 20
  37. MAGIC = 'ustar'
  38. VERSION = '00'
  39. LENGTH_NAME = 100
  40. LENGTH_LINK = 100
  41. LENGTH_PREFIX = 155
  42. MAXSIZE_MEMBER = 0x1FFFFFFFFL
  43. REGTYPE = '0'
  44. AREGTYPE = '\x00'
  45. LNKTYPE = '1'
  46. SYMTYPE = '2'
  47. CHRTYPE = '3'
  48. BLKTYPE = '4'
  49. DIRTYPE = '5'
  50. FIFOTYPE = '6'
  51. CONTTYPE = '7'
  52. GNUTYPE_LONGNAME = 'L'
  53. GNUTYPE_LONGLINK = 'K'
  54. GNUTYPE_SPARSE = 'S'
  55. SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, SYMTYPE, DIRTYPE, FIFOTYPE, CONTTYPE, CHRTYPE, BLKTYPE, GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, GNUTYPE_SPARSE)
  56. REGULAR_TYPES = (REGTYPE, AREGTYPE, CONTTYPE, GNUTYPE_SPARSE)
  57. S_IFLNK = 40960
  58. S_IFREG = 32768
  59. S_IFBLK = 24576
  60. S_IFDIR = 16384
  61. S_IFCHR = 8192
  62. S_IFIFO = 4096
  63. TSUID = 2048
  64. TSGID = 1024
  65. TSVTX = 512
  66. TUREAD = 256
  67. TUWRITE = 128
  68. TUEXEC = 64
  69. TGREAD = 32
  70. TGWRITE = 16
  71. TGEXEC = 8
  72. TOREAD = 4
  73. TOWRITE = 2
  74. TOEXEC = 1
  75.  
  76. def nts(s):
  77.     '''Convert a null-terminated string buffer to a python string.
  78.     '''
  79.     return s.rstrip(NUL)
  80.  
  81.  
  82. def calc_chksum(buf):
  83.     """Calculate the checksum for a member's header. It's a simple addition
  84.        of all bytes, treating the chksum field as if filled with spaces.
  85.        buf is a 512 byte long string buffer which holds the header.
  86.     """
  87.     chk = 256
  88.     for c in buf[:148]:
  89.         chk += ord(c)
  90.     
  91.     for c in buf[156:]:
  92.         chk += ord(c)
  93.     
  94.     return chk
  95.  
  96.  
  97. def copyfileobj(src, dst, length = None):
  98.     '''Copy length bytes from fileobj src to fileobj dst.
  99.        If length is None, copy the entire content.
  100.     '''
  101.     if length == 0:
  102.         return None
  103.     
  104.     if length is None:
  105.         shutil.copyfileobj(src, dst)
  106.         return None
  107.     
  108.     BUFSIZE = 16 * 1024
  109.     (blocks, remainder) = divmod(length, BUFSIZE)
  110.     for b in xrange(blocks):
  111.         buf = src.read(BUFSIZE)
  112.         if len(buf) < BUFSIZE:
  113.             raise IOError, 'end of file reached'
  114.         
  115.         dst.write(buf)
  116.     
  117.     if remainder != 0:
  118.         buf = src.read(remainder)
  119.         if len(buf) < remainder:
  120.             raise IOError, 'end of file reached'
  121.         
  122.         dst.write(buf)
  123.     
  124.  
  125. filemode_table = (((S_IFLNK, 'l'), (S_IFREG, '-'), (S_IFBLK, 'b'), (S_IFDIR, 'd'), (S_IFCHR, 'c'), (S_IFIFO, 'p')), ((TUREAD, 'r'),), ((TUWRITE, 'w'),), ((TUEXEC | TSUID, 's'), (TSUID, 'S'), (TUEXEC, 'x')), ((TGREAD, 'r'),), ((TGWRITE, 'w'),), ((TGEXEC | TSGID, 's'), (TSGID, 'S'), (TGEXEC, 'x')), ((TOREAD, 'r'),), ((TOWRITE, 'w'),), ((TOEXEC | TSVTX, 't'), (TSVTX, 'T'), (TOEXEC, 'x')))
  126.  
  127. def filemode(mode):
  128.     """Convert a file's mode to a string of the form
  129.        -rwxrwxrwx.
  130.        Used by TarFile.list()
  131.     """
  132.     perm = []
  133.     for table in filemode_table:
  134.         for bit, char in table:
  135.             if mode & bit == bit:
  136.                 perm.append(char)
  137.                 break
  138.                 continue
  139.         
  140.     
  141.     return ''.join(perm)
  142.  
  143. if os.sep != '/':
  144.     
  145.     normpath = lambda path: os.path.normpath(path).replace(os.sep, '/')
  146. else:
  147.     normpath = os.path.normpath
  148.  
  149. class TarError(Exception):
  150.     '''Base exception.'''
  151.     pass
  152.  
  153.  
  154. class ExtractError(TarError):
  155.     '''General exception for extract errors.'''
  156.     pass
  157.  
  158.  
  159. class ReadError(TarError):
  160.     '''Exception for unreadble tar archives.'''
  161.     pass
  162.  
  163.  
  164. class CompressionError(TarError):
  165.     '''Exception for unavailable compression methods.'''
  166.     pass
  167.  
  168.  
  169. class StreamError(TarError):
  170.     '''Exception for unsupported operations on stream-like TarFiles.'''
  171.     pass
  172.  
  173.  
  174. class _LowLevelFile:
  175.     '''Low-level file object. Supports reading and writing.
  176.        It is used instead of a regular file object for streaming
  177.        access.
  178.     '''
  179.     
  180.     def __init__(self, name, mode):
  181.         mode = {
  182.             'r': os.O_RDONLY,
  183.             'w': os.O_WRONLY | os.O_CREAT | os.O_TRUNC }[mode]
  184.         if hasattr(os, 'O_BINARY'):
  185.             mode |= os.O_BINARY
  186.         
  187.         self.fd = os.open(name, mode)
  188.  
  189.     
  190.     def close(self):
  191.         os.close(self.fd)
  192.  
  193.     
  194.     def read(self, size):
  195.         return os.read(self.fd, size)
  196.  
  197.     
  198.     def write(self, s):
  199.         os.write(self.fd, s)
  200.  
  201.  
  202.  
  203. class _Stream:
  204.     '''Class that serves as an adapter between TarFile and
  205.        a stream-like object.  The stream-like object only
  206.        needs to have a read() or write() method and is accessed
  207.        blockwise.  Use of gzip or bzip2 compression is possible.
  208.        A stream-like object could be for example: sys.stdin,
  209.        sys.stdout, a socket, a tape device etc.
  210.  
  211.        _Stream is intended to be used only internally.
  212.     '''
  213.     
  214.     def __init__(self, name, mode, type, fileobj, bufsize):
  215.         '''Construct a _Stream object.
  216.         '''
  217.         self._extfileobj = True
  218.         if fileobj is None:
  219.             fileobj = _LowLevelFile(name, mode)
  220.             self._extfileobj = False
  221.         
  222.         if not name:
  223.             pass
  224.         self.name = ''
  225.         self.mode = mode
  226.         self.type = type
  227.         self.fileobj = fileobj
  228.         self.bufsize = bufsize
  229.         self.buf = ''
  230.         self.pos = 0x0L
  231.         self.closed = False
  232.         if type == 'gz':
  233.             
  234.             try:
  235.                 import zlib as zlib
  236.             except ImportError:
  237.                 raise CompressionError, 'zlib module is not available'
  238.  
  239.             self.zlib = zlib
  240.             self.crc = zlib.crc32('')
  241.             if mode == 'r':
  242.                 self._init_read_gz()
  243.             else:
  244.                 self._init_write_gz()
  245.         
  246.         if type == 'bz2':
  247.             
  248.             try:
  249.                 import bz2
  250.             except ImportError:
  251.                 raise CompressionError, 'bz2 module is not available'
  252.  
  253.             if mode == 'r':
  254.                 self.dbuf = ''
  255.                 self.cmp = bz2.BZ2Decompressor()
  256.             else:
  257.                 self.cmp = bz2.BZ2Compressor()
  258.         
  259.  
  260.     
  261.     def __del__(self):
  262.         if not self.closed:
  263.             self.close()
  264.         
  265.  
  266.     
  267.     def _init_write_gz(self):
  268.         '''Initialize for writing with gzip compression.
  269.         '''
  270.         self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, -(self.zlib.MAX_WBITS), self.zlib.DEF_MEM_LEVEL, 0)
  271.         timestamp = struct.pack('<L', long(time.time()))
  272.         self._Stream__write('\x1f\x8b\x08\x08%s\x02\xff' % timestamp)
  273.         if self.name.endswith('.gz'):
  274.             self.name = self.name[:-3]
  275.         
  276.         self._Stream__write(self.name + NUL)
  277.  
  278.     
  279.     def write(self, s):
  280.         '''Write string s to the stream.
  281.         '''
  282.         if self.type == 'gz':
  283.             self.crc = self.zlib.crc32(s, self.crc)
  284.         
  285.         self.pos += len(s)
  286.         if self.type != 'tar':
  287.             s = self.cmp.compress(s)
  288.         
  289.         self._Stream__write(s)
  290.  
  291.     
  292.     def _Stream__write(self, s):
  293.         '''Write string s to the stream if a whole new block
  294.            is ready to be written.
  295.         '''
  296.         self.buf += s
  297.         while len(self.buf) > self.bufsize:
  298.             self.fileobj.write(self.buf[:self.bufsize])
  299.             self.buf = self.buf[self.bufsize:]
  300.             continue
  301.             self
  302.  
  303.     
  304.     def close(self):
  305.         '''Close the _Stream object. No operation should be
  306.            done on it afterwards.
  307.         '''
  308.         if self.closed:
  309.             return None
  310.         
  311.         if self.mode == 'w' and self.type != 'tar':
  312.             self.buf += self.cmp.flush()
  313.         
  314.         if self.mode == 'w' and self.buf:
  315.             self.fileobj.write(self.buf)
  316.             self.buf = ''
  317.             if self.type == 'gz':
  318.                 self.fileobj.write(struct.pack('<l', self.crc))
  319.                 self.fileobj.write(struct.pack('<L', self.pos & 0xFFFFFFFFL))
  320.             
  321.         
  322.         if not self._extfileobj:
  323.             self.fileobj.close()
  324.         
  325.         self.closed = True
  326.  
  327.     
  328.     def _init_read_gz(self):
  329.         '''Initialize for reading a gzip compressed fileobj.
  330.         '''
  331.         self.cmp = self.zlib.decompressobj(-(self.zlib.MAX_WBITS))
  332.         self.dbuf = ''
  333.         if self._Stream__read(2) != '\x1f\x8b':
  334.             raise ReadError, 'not a gzip file'
  335.         
  336.         if self._Stream__read(1) != '\x08':
  337.             raise CompressionError, 'unsupported compression method'
  338.         
  339.         flag = ord(self._Stream__read(1))
  340.         self._Stream__read(6)
  341.         if flag & 4:
  342.             xlen = ord(self._Stream__read(1)) + 256 * ord(self._Stream__read(1))
  343.             self.read(xlen)
  344.         
  345.         if flag & 8:
  346.             while True:
  347.                 s = self._Stream__read(1)
  348.                 if not s or s == NUL:
  349.                     break
  350.                     continue
  351.         
  352.         if flag & 16:
  353.             while True:
  354.                 s = self._Stream__read(1)
  355.                 if not s or s == NUL:
  356.                     break
  357.                     continue
  358.         
  359.         if flag & 2:
  360.             self._Stream__read(2)
  361.         
  362.  
  363.     
  364.     def tell(self):
  365.         """Return the stream's file pointer position.
  366.         """
  367.         return self.pos
  368.  
  369.     
  370.     def seek(self, pos = 0):
  371.         """Set the stream's file pointer to pos. Negative seeking
  372.            is forbidden.
  373.         """
  374.         if pos - self.pos >= 0:
  375.             (blocks, remainder) = divmod(pos - self.pos, self.bufsize)
  376.             for i in xrange(blocks):
  377.                 self.read(self.bufsize)
  378.             
  379.             self.read(remainder)
  380.         else:
  381.             raise StreamError, 'seeking backwards is not allowed'
  382.         return self.pos
  383.  
  384.     
  385.     def read(self, size = None):
  386.         '''Return the next size number of bytes from the stream.
  387.            If size is not defined, return all bytes of the stream
  388.            up to EOF.
  389.         '''
  390.         if size is None:
  391.             t = []
  392.             while True:
  393.                 buf = self._read(self.bufsize)
  394.                 if not buf:
  395.                     break
  396.                 
  397.                 t.append(buf)
  398.             buf = ''.join(t)
  399.         else:
  400.             buf = self._read(size)
  401.         self.pos += len(buf)
  402.         return buf
  403.  
  404.     
  405.     def _read(self, size):
  406.         '''Return size bytes from the stream.
  407.         '''
  408.         if self.type == 'tar':
  409.             return self._Stream__read(size)
  410.         
  411.         c = len(self.dbuf)
  412.         t = [
  413.             self.dbuf]
  414.         while c < size:
  415.             buf = self._Stream__read(self.bufsize)
  416.             if not buf:
  417.                 break
  418.             
  419.             buf = self.cmp.decompress(buf)
  420.             t.append(buf)
  421.             c += len(buf)
  422.         t = ''.join(t)
  423.         self.dbuf = t[size:]
  424.         return t[:size]
  425.  
  426.     
  427.     def _Stream__read(self, size):
  428.         '''Return size bytes from stream. If internal buffer is empty,
  429.            read another block from the stream.
  430.         '''
  431.         c = len(self.buf)
  432.         t = [
  433.             self.buf]
  434.         while c < size:
  435.             buf = self.fileobj.read(self.bufsize)
  436.             if not buf:
  437.                 break
  438.             
  439.             t.append(buf)
  440.             c += len(buf)
  441.         t = ''.join(t)
  442.         self.buf = t[size:]
  443.         return t[:size]
  444.  
  445.  
  446.  
  447. class ExFileObject(object):
  448.     '''File-like object for reading an archive member.
  449.        Is returned by TarFile.extractfile(). Support for
  450.        sparse files included.
  451.     '''
  452.     
  453.     def __init__(self, tarfile, tarinfo):
  454.         self.fileobj = tarfile.fileobj
  455.         self.name = tarinfo.name
  456.         self.mode = 'r'
  457.         self.closed = False
  458.         self.offset = tarinfo.offset_data
  459.         self.size = tarinfo.size
  460.         self.pos = 0x0L
  461.         self.linebuffer = ''
  462.         if tarinfo.issparse():
  463.             self.sparse = tarinfo.sparse
  464.             self.read = self._readsparse
  465.         else:
  466.             self.read = self._readnormal
  467.  
  468.     
  469.     def __read(self, size):
  470.         '''Overloadable read method.
  471.         '''
  472.         return self.fileobj.read(size)
  473.  
  474.     
  475.     def readline(self, size = -1):
  476.         '''Read a line with approx. size. If size is negative,
  477.            read a whole line. readline() and read() must not
  478.            be mixed up (!).
  479.         '''
  480.         if size < 0:
  481.             size = sys.maxint
  482.         
  483.         nl = self.linebuffer.find('\n')
  484.         if nl >= 0:
  485.             nl = min(nl, size)
  486.         else:
  487.             size -= len(self.linebuffer)
  488.             while nl < 0 and size > 0:
  489.                 buf = self.read(min(size, 100))
  490.                 if not buf:
  491.                     break
  492.                 
  493.                 self.linebuffer += buf
  494.                 size -= len(buf)
  495.                 nl = self.linebuffer.find('\n')
  496.                 continue
  497.                 self
  498.             if nl == -1:
  499.                 s = self.linebuffer
  500.                 self.linebuffer = ''
  501.                 return s
  502.             
  503.         buf = self.linebuffer[:nl]
  504.         self.linebuffer = self.linebuffer[nl + 1:]
  505.         while buf[-1:] == '\r':
  506.             buf = buf[:-1]
  507.         return buf + '\n'
  508.  
  509.     
  510.     def readlines(self):
  511.         '''Return a list with all (following) lines.
  512.         '''
  513.         result = []
  514.         while True:
  515.             line = self.readline()
  516.             if not line:
  517.                 break
  518.             
  519.             result.append(line)
  520.         return result
  521.  
  522.     
  523.     def _readnormal(self, size = None):
  524.         '''Read operation for regular files.
  525.         '''
  526.         if self.closed:
  527.             raise ValueError, 'file is closed'
  528.         
  529.         self.fileobj.seek(self.offset + self.pos)
  530.         bytesleft = self.size - self.pos
  531.         if size is None:
  532.             bytestoread = bytesleft
  533.         else:
  534.             bytestoread = min(size, bytesleft)
  535.         self.pos += bytestoread
  536.         return self._ExFileObject__read(bytestoread)
  537.  
  538.     
  539.     def _readsparse(self, size = None):
  540.         '''Read operation for sparse files.
  541.         '''
  542.         if self.closed:
  543.             raise ValueError, 'file is closed'
  544.         
  545.         if size is None:
  546.             size = self.size - self.pos
  547.         
  548.         data = []
  549.         while size > 0:
  550.             buf = self._readsparsesection(size)
  551.             if not buf:
  552.                 break
  553.             
  554.             size -= len(buf)
  555.             data.append(buf)
  556.         return ''.join(data)
  557.  
  558.     
  559.     def _readsparsesection(self, size):
  560.         '''Read a single section of a sparse file.
  561.         '''
  562.         section = self.sparse.find(self.pos)
  563.         if section is None:
  564.             return ''
  565.         
  566.         toread = min(size, section.offset + section.size - self.pos)
  567.  
  568.     
  569.     def tell(self):
  570.         '''Return the current file position.
  571.         '''
  572.         return self.pos
  573.  
  574.     
  575.     def seek(self, pos, whence = 0):
  576.         '''Seek to a position in the file.
  577.         '''
  578.         self.linebuffer = ''
  579.         if whence == 0:
  580.             self.pos = min(max(pos, 0), self.size)
  581.         
  582.         if whence == 1:
  583.             if pos < 0:
  584.                 self.pos = max(self.pos + pos, 0)
  585.             else:
  586.                 self.pos = min(self.pos + pos, self.size)
  587.         
  588.         if whence == 2:
  589.             self.pos = max(min(self.size + pos, self.size), 0)
  590.         
  591.  
  592.     
  593.     def close(self):
  594.         '''Close the file object.
  595.         '''
  596.         self.closed = True
  597.  
  598.  
  599.  
  600. class TarInfo(object):
  601.     '''Informational class which holds the details about an
  602.        archive member given by a tar header block.
  603.        TarInfo objects are returned by TarFile.getmember(),
  604.        TarFile.getmembers() and TarFile.gettarinfo() and are
  605.        usually created internally.
  606.     '''
  607.     
  608.     def __init__(self, name = ''):
  609.         '''Construct a TarInfo object. name is the optional name
  610.            of the member.
  611.         '''
  612.         self.name = name
  613.         self.mode = 438
  614.         self.uid = 0
  615.         self.gid = 0
  616.         self.size = 0
  617.         self.mtime = 0
  618.         self.chksum = 0
  619.         self.type = REGTYPE
  620.         self.linkname = ''
  621.         self.uname = 'user'
  622.         self.gname = 'group'
  623.         self.devmajor = 0
  624.         self.devminor = 0
  625.         self.prefix = ''
  626.         self.offset = 0
  627.         self.offset_data = 0
  628.  
  629.     
  630.     def __repr__(self):
  631.         return '<%s %r at %#x>' % (self.__class__.__name__, self.name, id(self))
  632.  
  633.     
  634.     def frombuf(cls, buf):
  635.         '''Construct a TarInfo object from a 512 byte string buffer.
  636.         '''
  637.         tarinfo = cls()
  638.         tarinfo.name = nts(buf[0:100])
  639.         tarinfo.mode = int(buf[100:108], 8)
  640.         tarinfo.uid = int(buf[108:116], 8)
  641.         tarinfo.gid = int(buf[116:124], 8)
  642.         tarinfo.mtime = long(buf[136:148], 8)
  643.         tarinfo.chksum = int(buf[148:156], 8)
  644.         tarinfo.type = buf[156:157]
  645.         tarinfo.linkname = nts(buf[157:257])
  646.         tarinfo.uname = nts(buf[265:297])
  647.         tarinfo.gname = nts(buf[297:329])
  648.         
  649.         try:
  650.             tarinfo.devmajor = int(buf[329:337], 8)
  651.             tarinfo.devminor = int(buf[337:345], 8)
  652.         except ValueError:
  653.             tarinfo if buf[124] != chr(128) else tarinfo
  654.             tarinfo if buf[124] != chr(128) else tarinfo
  655.             tarinfo.devmajor = tarinfo.devmajor = 0
  656.         except:
  657.             tarinfo if buf[124] != chr(128) else tarinfo
  658.  
  659.         tarinfo.prefix = buf[345:500]
  660.         if tarinfo.type != GNUTYPE_SPARSE:
  661.             tarinfo.name = normpath(os.path.join(nts(tarinfo.prefix), tarinfo.name))
  662.         
  663.         if tarinfo.isdir() and tarinfo.name[-1:] != '/':
  664.             tarinfo.name += '/'
  665.         
  666.         return tarinfo
  667.  
  668.     frombuf = classmethod(frombuf)
  669.     
  670.     def tobuf(self):
  671.         '''Return a tar header block as a 512 byte string.
  672.         '''
  673.         if self.size <= MAXSIZE_MEMBER:
  674.             size = '%011o' % self.size
  675.         else:
  676.             s = self.size
  677.             size = ''
  678.             for i in range(11):
  679.                 size = chr(s & 255) + size
  680.                 s >>= 8
  681.             
  682.             size = chr(128) + size
  683.         parts = []
  684.         for value, fieldsize in ((self.name, 100), ('%07o' % (self.mode & 4095), 8), ('%07o' % self.uid, 8), ('%07o' % self.gid, 8), (size, 12), ('%011o' % self.mtime, 12), ('        ', 8), (self.type, 1), (self.linkname, 100), (MAGIC, 6), (VERSION, 2), (self.uname, 32), (self.gname, 32), ('%07o' % self.devmajor, 8), ('%07o' % self.devminor, 8), (self.prefix, 155)):
  685.             l = len(value)
  686.             parts.append(value[:fieldsize] + (fieldsize - l) * NUL)
  687.         
  688.         buf = ''.join(parts)
  689.         chksum = calc_chksum(buf)
  690.         buf = buf[:148] + '%06o\x00' % chksum + buf[155:]
  691.         buf += (BLOCKSIZE - len(buf)) * NUL
  692.         self.buf = buf
  693.         return buf
  694.  
  695.     
  696.     def isreg(self):
  697.         return self.type in REGULAR_TYPES
  698.  
  699.     
  700.     def isfile(self):
  701.         return self.isreg()
  702.  
  703.     
  704.     def isdir(self):
  705.         return self.type == DIRTYPE
  706.  
  707.     
  708.     def issym(self):
  709.         return self.type == SYMTYPE
  710.  
  711.     
  712.     def islnk(self):
  713.         return self.type == LNKTYPE
  714.  
  715.     
  716.     def ischr(self):
  717.         return self.type == CHRTYPE
  718.  
  719.     
  720.     def isblk(self):
  721.         return self.type == BLKTYPE
  722.  
  723.     
  724.     def isfifo(self):
  725.         return self.type == FIFOTYPE
  726.  
  727.     
  728.     def issparse(self):
  729.         return self.type == GNUTYPE_SPARSE
  730.  
  731.     
  732.     def isdev(self):
  733.         return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE)
  734.  
  735.  
  736.  
  737. class TarFile(object):
  738.     '''The TarFile Class provides an interface to tar archives.
  739.     '''
  740.     debug = 0
  741.     dereference = False
  742.     ignore_zeros = False
  743.     errorlevel = 0
  744.     posix = False
  745.     fileobject = ExFileObject
  746.     
  747.     def __init__(self, name = None, mode = 'r', fileobj = None):
  748.         """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
  749.            read from an existing archive, 'a' to append data to an existing
  750.            file or 'w' to create a new file overwriting an existing one. `mode'
  751.            defaults to 'r'.
  752.            If `fileobj' is given, it is used for reading or writing data. If it
  753.            can be determined, `mode' is overridden by `fileobj's mode.
  754.            `fileobj' is not closed, when TarFile is closed.
  755.         """
  756.         self.name = name
  757.         if len(mode) > 1 or mode not in 'raw':
  758.             raise ValueError, "mode must be 'r', 'a' or 'w'"
  759.         
  760.         self._mode = mode
  761.         self.mode = {
  762.             'r': 'rb',
  763.             'a': 'r+b',
  764.             'w': 'wb' }[mode]
  765.         if not fileobj:
  766.             fileobj = file(self.name, self.mode)
  767.             self._extfileobj = False
  768.         elif self.name is None and hasattr(fileobj, 'name'):
  769.             self.name = fileobj.name
  770.         
  771.         if hasattr(fileobj, 'mode'):
  772.             self.mode = fileobj.mode
  773.         
  774.         self._extfileobj = True
  775.         self.fileobj = fileobj
  776.         self.closed = False
  777.         self.members = []
  778.         self._loaded = False
  779.         self.offset = 0x0L
  780.         self.inodes = { }
  781.         if self._mode == 'r':
  782.             self.firstmember = None
  783.             self.firstmember = self.next()
  784.         
  785.         if self._mode == 'a':
  786.             self.firstmember = None
  787.             while True:
  788.                 
  789.                 try:
  790.                     tarinfo = self.next()
  791.                 except ReadError:
  792.                     self.fileobj.seek(0)
  793.                     break
  794.  
  795.                 if tarinfo is None:
  796.                     self.fileobj.seek(-BLOCKSIZE, 1)
  797.                     break
  798.                     continue
  799.         
  800.         if self._mode in 'aw':
  801.             self._loaded = True
  802.         
  803.  
  804.     
  805.     def open(cls, name = None, mode = 'r', fileobj = None, bufsize = 20 * 512):
  806.         """Open a tar archive for reading, writing or appending. Return
  807.            an appropriate TarFile class.
  808.  
  809.            mode:
  810.            'r'          open for reading with transparent compression
  811.            'r:'         open for reading exclusively uncompressed
  812.            'r:gz'       open for reading with gzip compression
  813.            'r:bz2'      open for reading with bzip2 compression
  814.            'a' or 'a:'  open for appending
  815.            'w' or 'w:'  open for writing without compression
  816.            'w:gz'       open for writing with gzip compression
  817.            'w:bz2'      open for writing with bzip2 compression
  818.            'r|'         open an uncompressed stream of tar blocks for reading
  819.            'r|gz'       open a gzip compressed stream of tar blocks
  820.            'r|bz2'      open a bzip2 compressed stream of tar blocks
  821.            'w|'         open an uncompressed stream for writing
  822.            'w|gz'       open a gzip compressed stream for writing
  823.            'w|bz2'      open a bzip2 compressed stream for writing
  824.         """
  825.         if not name and not fileobj:
  826.             raise ValueError, 'nothing to open'
  827.         
  828.         if ':' in mode:
  829.             (filemode, comptype) = mode.split(':', 1)
  830.             if not filemode:
  831.                 pass
  832.             filemode = 'r'
  833.             if not comptype:
  834.                 pass
  835.             comptype = 'tar'
  836.             if comptype in cls.OPEN_METH:
  837.                 func = getattr(cls, cls.OPEN_METH[comptype])
  838.             else:
  839.                 raise CompressionError, 'unknown compression type %r' % comptype
  840.             return func(name, filemode, fileobj)
  841.         elif '|' in mode:
  842.             (filemode, comptype) = mode.split('|', 1)
  843.             if not filemode:
  844.                 pass
  845.             filemode = 'r'
  846.             if not comptype:
  847.                 pass
  848.             comptype = 'tar'
  849.             if filemode not in 'rw':
  850.                 raise ValueError, "mode must be 'r' or 'w'"
  851.             
  852.             t = cls(name, filemode, _Stream(name, filemode, comptype, fileobj, bufsize))
  853.             t._extfileobj = False
  854.             return t
  855.         elif mode == 'r':
  856.             for comptype in cls.OPEN_METH:
  857.                 func = getattr(cls, cls.OPEN_METH[comptype])
  858.                 
  859.                 try:
  860.                     return func(name, 'r', fileobj)
  861.                 continue
  862.                 except (ReadError, CompressionError):
  863.                     continue
  864.                     continue
  865.                 
  866.  
  867.             
  868.             raise ReadError, 'file could not be opened successfully'
  869.         elif mode in 'aw':
  870.             return cls.taropen(name, mode, fileobj)
  871.         
  872.         raise ValueError, 'undiscernible mode'
  873.  
  874.     open = classmethod(open)
  875.     
  876.     def taropen(cls, name, mode = 'r', fileobj = None):
  877.         '''Open uncompressed tar archive name for reading or writing.
  878.         '''
  879.         if len(mode) > 1 or mode not in 'raw':
  880.             raise ValueError, "mode must be 'r', 'a' or 'w'"
  881.         
  882.         return cls(name, mode, fileobj)
  883.  
  884.     taropen = classmethod(taropen)
  885.     
  886.     def gzopen(cls, name, mode = 'r', fileobj = None, compresslevel = 9):
  887.         '''Open gzip compressed tar archive name for reading or writing.
  888.            Appending is not allowed.
  889.         '''
  890.         if len(mode) > 1 or mode not in 'rw':
  891.             raise ValueError, "mode must be 'r' or 'w'"
  892.         
  893.         
  894.         try:
  895.             import gzip as gzip
  896.             gzip.GzipFile
  897.         except (ImportError, AttributeError):
  898.             raise CompressionError, 'gzip module is not available'
  899.  
  900.         (pre, ext) = os.path.splitext(name)
  901.         pre = os.path.basename(pre)
  902.         if ext == '.tgz':
  903.             ext = '.tar'
  904.         
  905.         if ext == '.gz':
  906.             ext = ''
  907.         
  908.         tarname = pre + ext
  909.         if fileobj is None:
  910.             fileobj = file(name, mode + 'b')
  911.         
  912.         if mode != 'r':
  913.             name = tarname
  914.         
  915.         
  916.         try:
  917.             t = cls.taropen(tarname, mode, gzip.GzipFile(name, mode, compresslevel, fileobj))
  918.         except IOError:
  919.             raise ReadError, 'not a gzip file'
  920.  
  921.         t._extfileobj = False
  922.         return t
  923.  
  924.     gzopen = classmethod(gzopen)
  925.     
  926.     def bz2open(cls, name, mode = 'r', fileobj = None, compresslevel = 9):
  927.         '''Open bzip2 compressed tar archive name for reading or writing.
  928.            Appending is not allowed.
  929.         '''
  930.         if len(mode) > 1 or mode not in 'rw':
  931.             raise ValueError, "mode must be 'r' or 'w'."
  932.         
  933.         
  934.         try:
  935.             import bz2
  936.         except ImportError:
  937.             raise CompressionError, 'bz2 module is not available'
  938.  
  939.         (pre, ext) = os.path.splitext(name)
  940.         pre = os.path.basename(pre)
  941.         if ext == '.tbz2':
  942.             ext = '.tar'
  943.         
  944.         if ext == '.bz2':
  945.             ext = ''
  946.         
  947.         tarname = pre + ext
  948.         if fileobj is not None:
  949.             raise ValueError, 'no support for external file objects'
  950.         
  951.         
  952.         try:
  953.             t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel = compresslevel))
  954.         except IOError:
  955.             raise ReadError, 'not a bzip2 file'
  956.  
  957.         t._extfileobj = False
  958.         return t
  959.  
  960.     bz2open = classmethod(bz2open)
  961.     OPEN_METH = {
  962.         'tar': 'taropen',
  963.         'gz': 'gzopen',
  964.         'bz2': 'bz2open' }
  965.     
  966.     def close(self):
  967.         '''Close the TarFile. In write-mode, two finishing zero blocks are
  968.            appended to the archive.
  969.         '''
  970.         if self.closed:
  971.             return None
  972.         
  973.         if self._mode in 'aw':
  974.             self.fileobj.write(NUL * BLOCKSIZE * 2)
  975.             self.offset += BLOCKSIZE * 2
  976.             (blocks, remainder) = divmod(self.offset, RECORDSIZE)
  977.             if remainder > 0:
  978.                 self.fileobj.write(NUL * (RECORDSIZE - remainder))
  979.             
  980.         
  981.         if not self._extfileobj:
  982.             self.fileobj.close()
  983.         
  984.         self.closed = True
  985.  
  986.     
  987.     def getmember(self, name):
  988.         """Return a TarInfo object for member `name'. If `name' can not be
  989.            found in the archive, KeyError is raised. If a member occurs more
  990.            than once in the archive, its last occurence is assumed to be the
  991.            most up-to-date version.
  992.         """
  993.         tarinfo = self._getmember(name)
  994.         if tarinfo is None:
  995.             raise KeyError, 'filename %r not found' % name
  996.         
  997.         return tarinfo
  998.  
  999.     
  1000.     def getmembers(self):
  1001.         '''Return the members of the archive as a list of TarInfo objects. The
  1002.            list has the same order as the members in the archive.
  1003.         '''
  1004.         self._check()
  1005.         if not self._loaded:
  1006.             self._load()
  1007.         
  1008.         return self.members
  1009.  
  1010.     
  1011.     def getnames(self):
  1012.         '''Return the members of the archive as a list of their names. It has
  1013.            the same order as the list returned by getmembers().
  1014.         '''
  1015.         return [ tarinfo.name for tarinfo in self.getmembers() ]
  1016.  
  1017.     
  1018.     def gettarinfo(self, name = None, arcname = None, fileobj = None):
  1019.         """Create a TarInfo object for either the file `name' or the file
  1020.            object `fileobj' (using os.fstat on its file descriptor). You can
  1021.            modify some of the TarInfo's attributes before you add it using
  1022.            addfile(). If given, `arcname' specifies an alternative name for the
  1023.            file in the archive.
  1024.         """
  1025.         self._check('aw')
  1026.         if fileobj is not None:
  1027.             name = fileobj.name
  1028.         
  1029.         if arcname is None:
  1030.             arcname = name
  1031.         
  1032.         arcname = normpath(arcname)
  1033.         (drv, arcname) = os.path.splitdrive(arcname)
  1034.         while arcname[0:1] == '/':
  1035.             arcname = arcname[1:]
  1036.         tarinfo = TarInfo()
  1037.         if fileobj is None:
  1038.             if hasattr(os, 'lstat') and not (self.dereference):
  1039.                 statres = os.lstat(name)
  1040.             else:
  1041.                 statres = os.stat(name)
  1042.         else:
  1043.             statres = os.fstat(fileobj.fileno())
  1044.         linkname = ''
  1045.         stmd = statres.st_mode
  1046.         if stat.S_ISREG(stmd):
  1047.             inode = (statres.st_ino, statres.st_dev)
  1048.             if inode in self.inodes and not (self.dereference):
  1049.                 type = LNKTYPE
  1050.                 linkname = self.inodes[inode]
  1051.             else:
  1052.                 type = REGTYPE
  1053.                 if inode[0]:
  1054.                     self.inodes[inode] = arcname
  1055.                 
  1056.         elif stat.S_ISDIR(stmd):
  1057.             type = DIRTYPE
  1058.             if arcname[-1:] != '/':
  1059.                 arcname += '/'
  1060.             
  1061.         elif stat.S_ISFIFO(stmd):
  1062.             type = FIFOTYPE
  1063.         elif stat.S_ISLNK(stmd):
  1064.             type = SYMTYPE
  1065.             linkname = os.readlink(name)
  1066.         elif stat.S_ISCHR(stmd):
  1067.             type = CHRTYPE
  1068.         elif stat.S_ISBLK(stmd):
  1069.             type = BLKTYPE
  1070.         else:
  1071.             return None
  1072.         tarinfo.name = arcname
  1073.         tarinfo.mode = stmd
  1074.         tarinfo.uid = statres.st_uid
  1075.         tarinfo.gid = statres.st_gid
  1076.         if stat.S_ISREG(stmd):
  1077.             tarinfo.size = statres.st_size
  1078.         else:
  1079.             tarinfo.size = 0x0L
  1080.         tarinfo.mtime = statres.st_mtime
  1081.         tarinfo.type = type
  1082.         tarinfo.linkname = linkname
  1083.         if pwd:
  1084.             
  1085.             try:
  1086.                 tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0]
  1087.             except KeyError:
  1088.                 pass
  1089.             except:
  1090.                 None<EXCEPTION MATCH>KeyError
  1091.             
  1092.  
  1093.         None<EXCEPTION MATCH>KeyError
  1094.         if grp:
  1095.             
  1096.             try:
  1097.                 tarinfo.gname = grp.getgrgid(tarinfo.gid)[0]
  1098.             except KeyError:
  1099.                 pass
  1100.             except:
  1101.                 None<EXCEPTION MATCH>KeyError
  1102.             
  1103.  
  1104.         None<EXCEPTION MATCH>KeyError
  1105.         if type in (CHRTYPE, BLKTYPE):
  1106.             if hasattr(os, 'major') and hasattr(os, 'minor'):
  1107.                 tarinfo.devmajor = os.major(statres.st_rdev)
  1108.                 tarinfo.devminor = os.minor(statres.st_rdev)
  1109.             
  1110.         
  1111.         return tarinfo
  1112.  
  1113.     
  1114.     def list(self, verbose = True):
  1115.         """Print a table of contents to sys.stdout. If `verbose' is False, only
  1116.            the names of the members are printed. If it is True, an `ls -l'-like
  1117.            output is produced.
  1118.         """
  1119.         self._check()
  1120.         for tarinfo in self:
  1121.             if verbose:
  1122.                 print filemode(tarinfo.mode), None % ('%s/%s', tarinfo.uid if not tarinfo.uname else tarinfo.gid),
  1123.                 if tarinfo.ischr() or tarinfo.isblk():
  1124.                     print '%10s' % '%d,%d' % (tarinfo.devmajor, tarinfo.devminor),
  1125.                 else:
  1126.                     print '%10d' % tarinfo.size,
  1127.                 print '%d-%02d-%02d %02d:%02d:%02d' % time.localtime(tarinfo.mtime)[:6],
  1128.             
  1129.             print tarinfo.name,
  1130.             if verbose:
  1131.                 if tarinfo.issym():
  1132.                     print '->', tarinfo.linkname,
  1133.                 
  1134.                 if tarinfo.islnk():
  1135.                     print 'link to', tarinfo.linkname,
  1136.                 
  1137.             
  1138.             print 
  1139.         
  1140.  
  1141.     
  1142.     def add(self, name, arcname = None, recursive = True):
  1143.         """Add the file `name' to the archive. `name' may be any type of file
  1144.            (directory, fifo, symbolic link, etc.). If given, `arcname'
  1145.            specifies an alternative name for the file in the archive.
  1146.            Directories are added recursively by default. This can be avoided by
  1147.            setting `recursive' to False.
  1148.         """
  1149.         self._check('aw')
  1150.         if arcname is None:
  1151.             arcname = name
  1152.         
  1153.         if self.name is not None and os.path.abspath(name) == os.path.abspath(self.name):
  1154.             self._dbg(2, 'tarfile: Skipped %r' % name)
  1155.             return None
  1156.         
  1157.         if name == '.':
  1158.             if recursive:
  1159.                 if arcname == '.':
  1160.                     arcname = ''
  1161.                 
  1162.                 for f in os.listdir('.'):
  1163.                     self.add(f, os.path.join(arcname, f))
  1164.                 
  1165.             
  1166.             return None
  1167.         
  1168.         self._dbg(1, name)
  1169.         tarinfo = self.gettarinfo(name, arcname)
  1170.         if tarinfo is None:
  1171.             self._dbg(1, 'tarfile: Unsupported type %r' % name)
  1172.             return None
  1173.         
  1174.         if tarinfo.isreg():
  1175.             f = file(name, 'rb')
  1176.             self.addfile(tarinfo, f)
  1177.             f.close()
  1178.         elif tarinfo.isdir():
  1179.             self.addfile(tarinfo)
  1180.             if recursive:
  1181.                 for f in os.listdir(name):
  1182.                     self.add(os.path.join(name, f), os.path.join(arcname, f))
  1183.                 
  1184.             
  1185.         else:
  1186.             self.addfile(tarinfo)
  1187.  
  1188.     
  1189.     def addfile(self, tarinfo, fileobj = None):
  1190.         """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
  1191.            given, tarinfo.size bytes are read from it and added to the archive.
  1192.            You can create TarInfo objects using gettarinfo().
  1193.            On Windows platforms, `fileobj' should always be opened with mode
  1194.            'rb' to avoid irritation about the file size.
  1195.         """
  1196.         self._check('aw')
  1197.         tarinfo.name = normpath(tarinfo.name)
  1198.         if tarinfo.isdir():
  1199.             tarinfo.name += '/'
  1200.         
  1201.         if tarinfo.linkname:
  1202.             tarinfo.linkname = normpath(tarinfo.linkname)
  1203.         
  1204.         if tarinfo.size > MAXSIZE_MEMBER:
  1205.             if self.posix:
  1206.                 raise ValueError, 'file is too large (>= 8 GB)'
  1207.             else:
  1208.                 self._dbg(2, 'tarfile: Created GNU tar largefile header')
  1209.         
  1210.         if len(tarinfo.linkname) > LENGTH_LINK:
  1211.             if self.posix:
  1212.                 raise ValueError, 'linkname is too long (>%d)' % LENGTH_LINK
  1213.             else:
  1214.                 self._create_gnulong(tarinfo.linkname, GNUTYPE_LONGLINK)
  1215.                 tarinfo.linkname = tarinfo.linkname[:LENGTH_LINK - 1]
  1216.                 self._dbg(2, 'tarfile: Created GNU tar extension LONGLINK')
  1217.         
  1218.         if len(tarinfo.name) > LENGTH_NAME:
  1219.             if self.posix:
  1220.                 prefix = tarinfo.name[:LENGTH_PREFIX + 1]
  1221.                 while prefix and prefix[-1] != '/':
  1222.                     prefix = prefix[:-1]
  1223.                 name = tarinfo.name[len(prefix):]
  1224.                 prefix = prefix[:-1]
  1225.                 if not prefix or len(name) > LENGTH_NAME:
  1226.                     raise ValueError, 'name is too long (>%d)' % LENGTH_NAME
  1227.                 
  1228.                 tarinfo.name = name
  1229.                 tarinfo.prefix = prefix
  1230.             else:
  1231.                 self._create_gnulong(tarinfo.name, GNUTYPE_LONGNAME)
  1232.                 tarinfo.name = tarinfo.name[:LENGTH_NAME - 1]
  1233.                 self._dbg(2, 'tarfile: Created GNU tar extension LONGNAME')
  1234.         
  1235.         self.fileobj.write(tarinfo.tobuf())
  1236.         self.offset += BLOCKSIZE
  1237.         if fileobj is not None:
  1238.             copyfileobj(fileobj, self.fileobj, tarinfo.size)
  1239.             (blocks, remainder) = divmod(tarinfo.size, BLOCKSIZE)
  1240.             if remainder > 0:
  1241.                 self.fileobj.write(NUL * (BLOCKSIZE - remainder))
  1242.                 blocks += 1
  1243.             
  1244.             self.offset += blocks * BLOCKSIZE
  1245.         
  1246.         self.members.append(tarinfo)
  1247.  
  1248.     
  1249.     def extract(self, member, path = ''):
  1250.         """Extract a member from the archive to the current working directory,
  1251.            using its full name. Its file information is extracted as accurately
  1252.            as possible. `member' may be a filename or a TarInfo object. You can
  1253.            specify a different directory using `path'.
  1254.         """
  1255.         self._check('r')
  1256.         if isinstance(member, TarInfo):
  1257.             tarinfo = member
  1258.         else:
  1259.             tarinfo = self.getmember(member)
  1260.         if tarinfo.islnk():
  1261.             tarinfo._link_target = os.path.join(path, tarinfo.linkname)
  1262.         
  1263.         
  1264.         try:
  1265.             self._extract_member(tarinfo, os.path.join(path, tarinfo.name))
  1266.         except EnvironmentError:
  1267.             e = None
  1268.             if self.errorlevel > 0:
  1269.                 raise 
  1270.             elif e.filename is None:
  1271.                 self._dbg(1, 'tarfile: %s' % e.strerror)
  1272.             else:
  1273.                 self._dbg(1, 'tarfile: %s %r' % (e.strerror, e.filename))
  1274.         except ExtractError:
  1275.             e = None
  1276.             if self.errorlevel > 1:
  1277.                 raise 
  1278.             else:
  1279.                 self._dbg(1, 'tarfile: %s' % e)
  1280.         except:
  1281.             self.errorlevel > 1
  1282.  
  1283.  
  1284.     
  1285.     def extractfile(self, member):
  1286.         """Extract a member from the archive as a file object. `member' may be
  1287.            a filename or a TarInfo object. If `member' is a regular file, a
  1288.            file-like object is returned. If `member' is a link, a file-like
  1289.            object is constructed from the link's target. If `member' is none of
  1290.            the above, None is returned.
  1291.            The file-like object is read-only and provides the following
  1292.            methods: read(), readline(), readlines(), seek() and tell()
  1293.         """
  1294.         self._check('r')
  1295.         if isinstance(member, TarInfo):
  1296.             tarinfo = member
  1297.         else:
  1298.             tarinfo = self.getmember(member)
  1299.         if tarinfo.isreg():
  1300.             return self.fileobject(self, tarinfo)
  1301.         elif tarinfo.type not in SUPPORTED_TYPES:
  1302.             return self.fileobject(self, tarinfo)
  1303.         elif tarinfo.islnk() or tarinfo.issym():
  1304.             if isinstance(self.fileobj, _Stream):
  1305.                 raise StreamError, 'cannot extract (sym)link as file object'
  1306.             else:
  1307.                 return self.extractfile(self._getmember(tarinfo.linkname, tarinfo))
  1308.         else:
  1309.             return None
  1310.  
  1311.     
  1312.     def _extract_member(self, tarinfo, targetpath):
  1313.         '''Extract the TarInfo object tarinfo to a physical
  1314.            file called targetpath.
  1315.         '''
  1316.         if targetpath[-1:] == '/':
  1317.             targetpath = targetpath[:-1]
  1318.         
  1319.         targetpath = os.path.normpath(targetpath)
  1320.         upperdirs = os.path.dirname(targetpath)
  1321.         if upperdirs and not os.path.exists(upperdirs):
  1322.             ti = TarInfo()
  1323.             ti.name = upperdirs
  1324.             ti.type = DIRTYPE
  1325.             ti.mode = 511
  1326.             ti.mtime = tarinfo.mtime
  1327.             ti.uid = tarinfo.uid
  1328.             ti.gid = tarinfo.gid
  1329.             ti.uname = tarinfo.uname
  1330.             ti.gname = tarinfo.gname
  1331.             
  1332.             try:
  1333.                 self._extract_member(ti, ti.name)
  1334.  
  1335.         
  1336.         if tarinfo.islnk() or tarinfo.issym():
  1337.             self._dbg(1, '%s -> %s' % (tarinfo.name, tarinfo.linkname))
  1338.         else:
  1339.             self._dbg(1, tarinfo.name)
  1340.         if tarinfo.isreg():
  1341.             self.makefile(tarinfo, targetpath)
  1342.         elif tarinfo.isdir():
  1343.             self.makedir(tarinfo, targetpath)
  1344.         elif tarinfo.isfifo():
  1345.             self.makefifo(tarinfo, targetpath)
  1346.         elif tarinfo.ischr() or tarinfo.isblk():
  1347.             self.makedev(tarinfo, targetpath)
  1348.         elif tarinfo.islnk() or tarinfo.issym():
  1349.             self.makelink(tarinfo, targetpath)
  1350.         elif tarinfo.type not in SUPPORTED_TYPES:
  1351.             self.makeunknown(tarinfo, targetpath)
  1352.         else:
  1353.             self.makefile(tarinfo, targetpath)
  1354.         self.chown(tarinfo, targetpath)
  1355.         if not tarinfo.issym():
  1356.             self.chmod(tarinfo, targetpath)
  1357.             self.utime(tarinfo, targetpath)
  1358.         
  1359.  
  1360.     
  1361.     def makedir(self, tarinfo, targetpath):
  1362.         '''Make a directory called targetpath.
  1363.         '''
  1364.         
  1365.         try:
  1366.             os.mkdir(targetpath)
  1367.         except EnvironmentError:
  1368.             e = None
  1369.             if e.errno != errno.EEXIST:
  1370.                 raise 
  1371.             
  1372.         except:
  1373.             e.errno != errno.EEXIST
  1374.  
  1375.  
  1376.     
  1377.     def makefile(self, tarinfo, targetpath):
  1378.         '''Make a file called targetpath.
  1379.         '''
  1380.         source = self.extractfile(tarinfo)
  1381.         target = file(targetpath, 'wb')
  1382.         copyfileobj(source, target)
  1383.         source.close()
  1384.         target.close()
  1385.  
  1386.     
  1387.     def makeunknown(self, tarinfo, targetpath):
  1388.         '''Make a file from a TarInfo object with an unknown type
  1389.            at targetpath.
  1390.         '''
  1391.         self.makefile(tarinfo, targetpath)
  1392.         self._dbg(1, 'tarfile: Unknown file type %r, extracted as regular file.' % tarinfo.type)
  1393.  
  1394.     
  1395.     def makefifo(self, tarinfo, targetpath):
  1396.         '''Make a fifo called targetpath.
  1397.         '''
  1398.         if hasattr(os, 'mkfifo'):
  1399.             os.mkfifo(targetpath)
  1400.         else:
  1401.             raise ExtractError, 'fifo not supported by system'
  1402.  
  1403.     
  1404.     def makedev(self, tarinfo, targetpath):
  1405.         '''Make a character or block device called targetpath.
  1406.         '''
  1407.         if not hasattr(os, 'mknod') or not hasattr(os, 'makedev'):
  1408.             raise ExtractError, 'special devices not supported by system'
  1409.         
  1410.         mode = tarinfo.mode
  1411.         if tarinfo.isblk():
  1412.             mode |= stat.S_IFBLK
  1413.         else:
  1414.             mode |= stat.S_IFCHR
  1415.         os.mknod(targetpath, mode, os.makedev(tarinfo.devmajor, tarinfo.devminor))
  1416.  
  1417.     
  1418.     def makelink(self, tarinfo, targetpath):
  1419.         '''Make a (symbolic) link called targetpath. If it cannot be created
  1420.           (platform limitation), we try to make a copy of the referenced file
  1421.           instead of a link.
  1422.         '''
  1423.         linkpath = tarinfo.linkname
  1424.         
  1425.         try:
  1426.             if tarinfo.issym():
  1427.                 os.symlink(linkpath, targetpath)
  1428.             else:
  1429.                 os.link(tarinfo._link_target, targetpath)
  1430.         except AttributeError:
  1431.             if tarinfo.issym():
  1432.                 linkpath = os.path.join(os.path.dirname(tarinfo.name), linkpath)
  1433.                 linkpath = normpath(linkpath)
  1434.             
  1435.             
  1436.             try:
  1437.                 self._extract_member(self.getmember(linkpath), targetpath)
  1438.             except (EnvironmentError, KeyError):
  1439.                 e = None
  1440.                 linkpath = os.path.normpath(linkpath)
  1441.                 
  1442.                 try:
  1443.                     shutil.copy2(linkpath, targetpath)
  1444.                 except EnvironmentError:
  1445.                     e = None
  1446.                     raise IOError, 'link could not be created'
  1447.                 except:
  1448.                     None<EXCEPTION MATCH>EnvironmentError
  1449.                 
  1450.  
  1451.                 None<EXCEPTION MATCH>EnvironmentError
  1452.             
  1453.  
  1454.             None<EXCEPTION MATCH>(EnvironmentError, KeyError)
  1455.  
  1456.  
  1457.     
  1458.     def chown(self, tarinfo, targetpath):
  1459.         '''Set owner of targetpath according to tarinfo.
  1460.         '''
  1461.         if pwd and hasattr(os, 'geteuid') and os.geteuid() == 0:
  1462.             
  1463.             try:
  1464.                 g = grp.getgrnam(tarinfo.gname)[2]
  1465.             except KeyError:
  1466.                 
  1467.                 try:
  1468.                     g = grp.getgrgid(tarinfo.gid)[2]
  1469.                 except KeyError:
  1470.                     g = os.getgid()
  1471.                 except:
  1472.                     None<EXCEPTION MATCH>KeyError
  1473.                 
  1474.  
  1475.                 None<EXCEPTION MATCH>KeyError
  1476.  
  1477.             
  1478.             try:
  1479.                 u = pwd.getpwnam(tarinfo.uname)[2]
  1480.             except KeyError:
  1481.                 
  1482.                 try:
  1483.                     u = pwd.getpwuid(tarinfo.uid)[2]
  1484.                 except KeyError:
  1485.                     u = os.getuid()
  1486.                 except:
  1487.                     None<EXCEPTION MATCH>KeyError
  1488.                 
  1489.  
  1490.                 None<EXCEPTION MATCH>KeyError
  1491.  
  1492.             
  1493.             try:
  1494.                 if tarinfo.issym() and hasattr(os, 'lchown'):
  1495.                     os.lchown(targetpath, u, g)
  1496.                 elif sys.platform != 'os2emx':
  1497.                     os.chown(targetpath, u, g)
  1498.             except EnvironmentError:
  1499.                 e = None
  1500.                 raise ExtractError, 'could not change owner'
  1501.             except:
  1502.                 None<EXCEPTION MATCH>EnvironmentError
  1503.             
  1504.  
  1505.         None<EXCEPTION MATCH>EnvironmentError
  1506.  
  1507.     
  1508.     def chmod(self, tarinfo, targetpath):
  1509.         '''Set file permissions of targetpath according to tarinfo.
  1510.         '''
  1511.         if hasattr(os, 'chmod'):
  1512.             
  1513.             try:
  1514.                 os.chmod(targetpath, tarinfo.mode)
  1515.             except EnvironmentError:
  1516.                 e = None
  1517.                 raise ExtractError, 'could not change mode'
  1518.             except:
  1519.                 None<EXCEPTION MATCH>EnvironmentError
  1520.             
  1521.  
  1522.         None<EXCEPTION MATCH>EnvironmentError
  1523.  
  1524.     
  1525.     def utime(self, tarinfo, targetpath):
  1526.         '''Set modification time of targetpath according to tarinfo.
  1527.         '''
  1528.         if not hasattr(os, 'utime'):
  1529.             return None
  1530.         
  1531.         if sys.platform == 'win32' and tarinfo.isdir():
  1532.             return None
  1533.         
  1534.         
  1535.         try:
  1536.             os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
  1537.         except EnvironmentError:
  1538.             e = None
  1539.             raise ExtractError, 'could not change modification time'
  1540.  
  1541.  
  1542.     
  1543.     def next(self):
  1544.         '''Return the next member of the archive as a TarInfo object, when
  1545.            TarFile is opened for reading. Return None if there is no more
  1546.            available.
  1547.         '''
  1548.         self._check('ra')
  1549.         if self.firstmember is not None:
  1550.             m = self.firstmember
  1551.             self.firstmember = None
  1552.             return m
  1553.         
  1554.         self.fileobj.seek(self.offset)
  1555.         while True:
  1556.             buf = self.fileobj.read(BLOCKSIZE)
  1557.             if not buf:
  1558.                 return None
  1559.             
  1560.             
  1561.             try:
  1562.                 tarinfo = TarInfo.frombuf(buf)
  1563.             except ValueError:
  1564.                 if self.ignore_zeros:
  1565.                     if buf.count(NUL) == BLOCKSIZE:
  1566.                         adj = 'empty'
  1567.                     else:
  1568.                         adj = 'invalid'
  1569.                     self._dbg(2, '0x%X: %s block' % (self.offset, adj))
  1570.                     self.offset += BLOCKSIZE
  1571.                     continue
  1572.                 elif self.offset == 0:
  1573.                     raise ReadError, 'empty, unreadable or compressed file'
  1574.                 
  1575.                 return None
  1576.  
  1577.             break
  1578.         if tarinfo.chksum != calc_chksum(buf):
  1579.             self._dbg(1, 'tarfile: Bad Checksum %r' % tarinfo.name)
  1580.         
  1581.         tarinfo.offset = self.offset
  1582.         self.offset += BLOCKSIZE
  1583.         if tarinfo.type in self.TYPE_METH:
  1584.             return self.TYPE_METH[tarinfo.type](self, tarinfo)
  1585.         
  1586.         tarinfo.offset_data = self.offset
  1587.         if tarinfo.isreg() or tarinfo.type not in SUPPORTED_TYPES:
  1588.             self.offset += self._block(tarinfo.size)
  1589.         
  1590.         if tarinfo.isreg() and tarinfo.name[:-1] == '/':
  1591.             tarinfo.type = DIRTYPE
  1592.         
  1593.         self.members.append(tarinfo)
  1594.         return tarinfo
  1595.  
  1596.     
  1597.     def proc_gnulong(self, tarinfo):
  1598.         '''Evaluate the blocks that hold a GNU longname
  1599.            or longlink member.
  1600.         '''
  1601.         buf = ''
  1602.         count = tarinfo.size
  1603.         while count > 0:
  1604.             block = self.fileobj.read(BLOCKSIZE)
  1605.             buf += block
  1606.             self.offset += BLOCKSIZE
  1607.             count -= BLOCKSIZE
  1608.             continue
  1609.             self
  1610.         next = self.next()
  1611.         next.offset = tarinfo.offset
  1612.         if tarinfo.type == GNUTYPE_LONGNAME:
  1613.             next.name = nts(buf)
  1614.         elif tarinfo.type == GNUTYPE_LONGLINK:
  1615.             next.linkname = nts(buf)
  1616.         
  1617.         return next
  1618.  
  1619.     
  1620.     def proc_sparse(self, tarinfo):
  1621.         '''Analyze a GNU sparse header plus extra headers.
  1622.         '''
  1623.         buf = tarinfo.tobuf()
  1624.         sp = _ringbuffer()
  1625.         pos = 386
  1626.         lastpos = 0x0L
  1627.         realpos = 0x0L
  1628.         for i in xrange(4):
  1629.             
  1630.             try:
  1631.                 offset = int(buf[pos:pos + 12], 8)
  1632.                 numbytes = int(buf[pos + 12:pos + 24], 8)
  1633.             except ValueError:
  1634.                 break
  1635.  
  1636.             if offset > lastpos:
  1637.                 sp.append(_hole(lastpos, offset - lastpos))
  1638.             
  1639.             sp.append(_data(offset, numbytes, realpos))
  1640.             realpos += numbytes
  1641.             lastpos = offset + numbytes
  1642.             pos += 24
  1643.         
  1644.         isextended = ord(buf[482])
  1645.         origsize = int(buf[483:495], 8)
  1646.         while isextended == 1:
  1647.             buf = self.fileobj.read(BLOCKSIZE)
  1648.             self.offset += BLOCKSIZE
  1649.             pos = 0
  1650.             for i in xrange(21):
  1651.                 
  1652.                 try:
  1653.                     offset = int(buf[pos:pos + 12], 8)
  1654.                     numbytes = int(buf[pos + 12:pos + 24], 8)
  1655.                 except ValueError:
  1656.                     self
  1657.                     self
  1658.                     break
  1659.                 except:
  1660.                     self
  1661.  
  1662.                 if offset > lastpos:
  1663.                     sp.append(_hole(lastpos, offset - lastpos))
  1664.                 
  1665.                 sp.append(_data(offset, numbytes, realpos))
  1666.                 realpos += numbytes
  1667.                 lastpos = offset + numbytes
  1668.                 pos += 24
  1669.             
  1670.             isextended = ord(buf[504])
  1671.         if lastpos < origsize:
  1672.             sp.append(_hole(lastpos, origsize - lastpos))
  1673.         
  1674.         tarinfo.sparse = sp
  1675.         tarinfo.offset_data = self.offset
  1676.         self.offset += self._block(tarinfo.size)
  1677.         tarinfo.size = origsize
  1678.         self.members.append(tarinfo)
  1679.         return tarinfo
  1680.  
  1681.     TYPE_METH = {
  1682.         GNUTYPE_LONGNAME: proc_gnulong,
  1683.         GNUTYPE_LONGLINK: proc_gnulong,
  1684.         GNUTYPE_SPARSE: proc_sparse }
  1685.     
  1686.     def _block(self, count):
  1687.         '''Round up a byte count by BLOCKSIZE and return it,
  1688.            e.g. _block(834) => 1024.
  1689.         '''
  1690.         (blocks, remainder) = divmod(count, BLOCKSIZE)
  1691.         if remainder:
  1692.             blocks += 1
  1693.         
  1694.         return blocks * BLOCKSIZE
  1695.  
  1696.     
  1697.     def _getmember(self, name, tarinfo = None):
  1698.         '''Find an archive member by name from bottom to top.
  1699.            If tarinfo is given, it is used as the starting point.
  1700.         '''
  1701.         members = self.getmembers()
  1702.         if tarinfo is None:
  1703.             end = len(members)
  1704.         else:
  1705.             end = members.index(tarinfo)
  1706.         for i in xrange(end - 1, -1, -1):
  1707.             if name == members[i].name:
  1708.                 return members[i]
  1709.                 continue
  1710.         
  1711.  
  1712.     
  1713.     def _load(self):
  1714.         '''Read through the entire archive file and look for readable
  1715.            members.
  1716.         '''
  1717.         while True:
  1718.             tarinfo = self.next()
  1719.             if tarinfo is None:
  1720.                 break
  1721.                 continue
  1722.         self._loaded = True
  1723.  
  1724.     
  1725.     def _check(self, mode = None):
  1726.         """Check if TarFile is still open, and if the operation's mode
  1727.            corresponds to TarFile's mode.
  1728.         """
  1729.         if self.closed:
  1730.             raise IOError, '%s is closed' % self.__class__.__name__
  1731.         
  1732.         if mode is not None and self._mode not in mode:
  1733.             raise IOError, 'bad operation for mode %r' % self._mode
  1734.         
  1735.  
  1736.     
  1737.     def __iter__(self):
  1738.         '''Provide an iterator object.
  1739.         '''
  1740.         if self._loaded:
  1741.             return iter(self.members)
  1742.         else:
  1743.             return TarIter(self)
  1744.  
  1745.     
  1746.     def _create_gnulong(self, name, type):
  1747.         '''Write a GNU longname/longlink member to the TarFile.
  1748.            It consists of an extended tar header, with the length
  1749.            of the longname as size, followed by data blocks,
  1750.            which contain the longname as a null terminated string.
  1751.         '''
  1752.         name += NUL
  1753.         tarinfo = TarInfo()
  1754.         tarinfo.name = '././@LongLink'
  1755.         tarinfo.type = type
  1756.         tarinfo.mode = 0
  1757.         tarinfo.size = len(name)
  1758.         self.fileobj.write(tarinfo.tobuf())
  1759.         self.offset += BLOCKSIZE
  1760.         self.fileobj.write(name)
  1761.         (blocks, remainder) = divmod(tarinfo.size, BLOCKSIZE)
  1762.         if remainder > 0:
  1763.             self.fileobj.write(NUL * (BLOCKSIZE - remainder))
  1764.             blocks += 1
  1765.         
  1766.         self.offset += blocks * BLOCKSIZE
  1767.  
  1768.     
  1769.     def _dbg(self, level, msg):
  1770.         '''Write debugging output to sys.stderr.
  1771.         '''
  1772.         if level <= self.debug:
  1773.             print >>sys.stderr, msg
  1774.         
  1775.  
  1776.  
  1777.  
  1778. class TarIter:
  1779.     '''Iterator Class.
  1780.  
  1781.        for tarinfo in TarFile(...):
  1782.            suite...
  1783.     '''
  1784.     
  1785.     def __init__(self, tarfile):
  1786.         '''Construct a TarIter object.
  1787.         '''
  1788.         self.tarfile = tarfile
  1789.         self.index = 0
  1790.  
  1791.     
  1792.     def __iter__(self):
  1793.         '''Return iterator object.
  1794.         '''
  1795.         return self
  1796.  
  1797.     
  1798.     def next(self):
  1799.         """Return the next item using TarFile's next() method.
  1800.            When all members have been read, set TarFile as _loaded.
  1801.         """
  1802.         if not self.tarfile._loaded:
  1803.             tarinfo = self.tarfile.next()
  1804.             if not tarinfo:
  1805.                 self.tarfile._loaded = True
  1806.                 raise StopIteration
  1807.             
  1808.         else:
  1809.             
  1810.             try:
  1811.                 tarinfo = self.tarfile.members[self.index]
  1812.             except IndexError:
  1813.                 raise StopIteration
  1814.  
  1815.         self.index += 1
  1816.         return tarinfo
  1817.  
  1818.  
  1819.  
  1820. class _section:
  1821.     '''Base class for _data and _hole.
  1822.     '''
  1823.     
  1824.     def __init__(self, offset, size):
  1825.         self.offset = offset
  1826.         self.size = size
  1827.  
  1828.     
  1829.     def __contains__(self, offset):
  1830.         return None if offset <= offset else offset < self.offset + self.size
  1831.  
  1832.  
  1833.  
  1834. class _data(_section):
  1835.     '''Represent a data section in a sparse file.
  1836.     '''
  1837.     
  1838.     def __init__(self, offset, size, realpos):
  1839.         _section.__init__(self, offset, size)
  1840.         self.realpos = realpos
  1841.  
  1842.  
  1843.  
  1844. class _hole(_section):
  1845.     '''Represent a hole section in a sparse file.
  1846.     '''
  1847.     pass
  1848.  
  1849.  
  1850. class _ringbuffer(list):
  1851.     '''Ringbuffer class which increases performance
  1852.        over a regular list.
  1853.     '''
  1854.     
  1855.     def __init__(self):
  1856.         self.idx = 0
  1857.  
  1858.     
  1859.     def find(self, offset):
  1860.         idx = self.idx
  1861.         while True:
  1862.             item = self[idx]
  1863.             if offset in item:
  1864.                 break
  1865.             
  1866.             idx += 1
  1867.             if idx == len(self):
  1868.                 idx = 0
  1869.             
  1870.             if idx == self.idx:
  1871.                 return None
  1872.                 continue
  1873.         self.idx = idx
  1874.         return item
  1875.  
  1876.  
  1877. TAR_PLAIN = 0
  1878. TAR_GZIPPED = 8
  1879.  
  1880. class TarFileCompat:
  1881.     """TarFile class compatible with standard module zipfile's
  1882.        ZipFile class.
  1883.     """
  1884.     
  1885.     def __init__(self, file, mode = 'r', compression = TAR_PLAIN):
  1886.         if compression == TAR_PLAIN:
  1887.             self.tarfile = TarFile.taropen(file, mode)
  1888.         elif compression == TAR_GZIPPED:
  1889.             self.tarfile = TarFile.gzopen(file, mode)
  1890.         else:
  1891.             raise ValueError, 'unknown compression constant'
  1892.         if mode[0:1] == 'r':
  1893.             members = self.tarfile.getmembers()
  1894.             for i in xrange(len(members)):
  1895.                 m = members[i]
  1896.                 m.filename = m.name
  1897.                 m.file_size = m.size
  1898.                 m.date_time = time.gmtime(m.mtime)[:6]
  1899.             
  1900.         
  1901.  
  1902.     
  1903.     def namelist(self):
  1904.         return map((lambda m: m.name), self.infolist())
  1905.  
  1906.     
  1907.     def infolist(self):
  1908.         return filter((lambda m: m.type in REGULAR_TYPES), self.tarfile.getmembers())
  1909.  
  1910.     
  1911.     def printdir(self):
  1912.         self.tarfile.list()
  1913.  
  1914.     
  1915.     def testzip(self):
  1916.         pass
  1917.  
  1918.     
  1919.     def getinfo(self, name):
  1920.         return self.tarfile.getmember(name)
  1921.  
  1922.     
  1923.     def read(self, name):
  1924.         return self.tarfile.extractfile(self.tarfile.getmember(name)).read()
  1925.  
  1926.     
  1927.     def write(self, filename, arcname = None, compress_type = None):
  1928.         self.tarfile.add(filename, arcname)
  1929.  
  1930.     
  1931.     def writestr(self, zinfo, bytes):
  1932.         import StringIO as StringIO
  1933.         import calendar as calendar
  1934.         zinfo.name = zinfo.filename
  1935.         zinfo.size = zinfo.file_size
  1936.         zinfo.mtime = calendar.timegm(zinfo.date_time)
  1937.         self.tarfile.addfile(zinfo, StringIO.StringIO(bytes))
  1938.  
  1939.     
  1940.     def close(self):
  1941.         self.tarfile.close()
  1942.  
  1943.  
  1944.  
  1945. def is_tarfile(name):
  1946.     '''Return True if name points to a tar archive that we
  1947.        are able to handle, else return False.
  1948.     '''
  1949.     
  1950.     try:
  1951.         t = open(name)
  1952.         t.close()
  1953.         return True
  1954.     except TarError:
  1955.         return False
  1956.  
  1957.  
  1958. open = TarFile.open
  1959.